//
//  unordered_pair.h
//  math
//
//  Created by Sam Jaffe on 11/2/12.
//  Copyright (c) 2012 Sam Jaffe. All rights reserved.
//

#pragma once
#include <utility>
#include <tuple>

#pragma mark class definitions
//namespace std {
    
    template <class T>
    struct unordered_pair : public std::pair<T, T> {
        constexpr unordered_pair() : //(1)
        std::pair<T, T>() {
            
        } 
        
        unordered_pair( const T& x, const T& y ) : //(2)
        std::pair<T, T>(x, y) {
            
        } 
        
        template< class U >
        unordered_pair( U&& x, U&& y ) : //(3)
        std::pair<T, T>(x, y) {
            
        } 
        
        template< class U >
        unordered_pair( const unordered_pair<U>& p ) : //(4)
        std::pair<T, T>(p) {
            
        } 
        
        template< class U >
        unordered_pair( const std::pair<U, U>& p ) :
        std::pair<T, T>(p) {
            
        }
        
        template< class U >
        unordered_pair( unordered_pair<U>&& p ) : //(5)
        std::pair<T, T>(p) {
            
        } 
        
        template< class U >
        unordered_pair( std::pair<U, U>&& p ) :
        std::pair<T, T>(p) {
            
        }
        
        template< class... _Tp_args >
        unordered_pair( std::piecewise_construct_t, //(6)
                       std::tuple<_Tp_args...> first_args,
                       std::tuple<_Tp_args...> second_args ) :
        std::pair<T, T>(std::piecewise_construct, first_args, second_args) {
            
        } 
        
        unordered_pair( const unordered_pair& p ) = default; //(7)
        
        unordered_pair( const std::pair<T, T>& p ) :
        std::pair<T, T>(p) {
            
        }
        
        unordered_pair( unordered_pair&& p ) = default; //(8)
        
        unordered_pair( std::pair<T, T>&& p ) :
        std::pair<T, T>(p) {
            
        }
        
        void swap(unordered_pair<T>& other) {
            if (noexcept(
                         noexcept(std::swap(std::pair<T, T>::first, other.first)) &&
                         noexcept(std::swap(std::pair<T, T>::second, other.second))
                         )
                );
        }
        
        unordered_pair& operator=( const unordered_pair<T>& other ) = default; //(1)
        
        template <class U>
        unordered_pair& operator=( const unordered_pair<U>& other ); //(2)
        
        unordered_pair& operator=( unordered_pair<T>&& other ) = default; //(3)
        
        template <class U>
        unordered_pair& operator=( unordered_pair<U>&& other ); //(4)
        
        bool operator == (const unordered_pair<T>& other) const {
            return std::pair<T, T>::operator==(other) ||
            (other.first == std::pair<T, T>::second &&
             other.second == std::pair<T, T>::first);
        }
        
        bool operator != (const unordered_pair<T>& other) const {
            return std::pair<T, T>::operator!=(other) &&
            (other.first != std::pair<T, T>::second &&
             other.second != std::pair<T, T>::first);
        }
                
    };
    
    //}
